home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / common / loader.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  29KB  |  999 lines

  1. /*
  2.  * static char *rcsid_object_c =
  3.  *   "$Id: loader.c,v 1.33 1996/07/24 07:03:10 master Exp master $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
  30.    sub/add_weight will transcend the environment updating the carrying
  31.    variable. */
  32.  
  33. #include <global.h>
  34. #include <loader.h>
  35.  
  36. /* All the variable names.  Each entry should correspond to the 
  37.  * V_ vlaue in loader.h (that is, the 20'th value in this array should
  38.  * correspond to the 20'th V_(value) in loader.h)
  39.  */
  40.  
  41. /* If you change this list (add/delete/rename), also update the list
  42.  * in crossedit/Attr.c, around line 360.  That list is the variables
  43.  * that can be set in crossedit for various objects.
  44.  */
  45. static char *variable_const[NR_OF_VARIABLES] = {
  46.   "Object","name","race","slaying","msg","endmsg",
  47.   "Inventory","arch","other_arch","More",
  48.   "anim","mina","end","last_heal","last_sp","last_eat",
  49.   "speed","speed_left","slow_move",
  50.   "face","Str","Dex","Con","Wis","Cha","Int","Pow","hp","maxhp","sp","maxsp",
  51.   "grace","maxgrace",
  52.   "exp","food","dam","wc","ac","x","y","nrof","level","direction",
  53.   "type","material","value", "weight","carrying",
  54.   "immune","protected","attacktype","vulnerable",
  55.   "path_attuned","path_repelled","path_denied",
  56.   "invisible","magic","state","alive","applied","unpaid","need_an","need_ie",
  57.   "no_pick","no_pass","walk_on","walk_off","fly_on","fly_off","is_animated",
  58.   "flying","monster", "friendly","generator","auto_apply","treasure",
  59.   "apply_once","see_invisible","can_roll","is_turning","is_turnable",
  60.   "is_used_up","identified","reflecting","changing","splitting","hitback",
  61.   "startequip","blocksview","editable","undead","scared","unaggressive",
  62.   "color_fg","color_bg","reflect_missile","reflect_spell","no_magic",
  63.   "wiz","was_wiz","no_fix_player","tear_down", "luck", "run_away","pass_thru",
  64.   "can_pass_thru","pick_up","anim_speed","container","no_drop",
  65.   "no_pretext","will_apply","random_movement", "can_apply",
  66.   "can_cast_spell","can_use_scroll","can_use_wand","can_use_bow",
  67.   "can_use_armour","can_use_weapon","can_use_ring","has_ready_wand",
  68.   "has_ready_bow","xrays","is_floor","lifesave","no_strength",
  69.   "sleep","stand_still","random_move","only_attack","armour",
  70.   "attack_movement","move_state","confused","stealth","connected",
  71.   "cursed","damned","see_anywhere","known_magical","known_cursed",
  72.   "can_steal","been_applied","title","has_ready_rod","can_use_rod",
  73.   "has_ready_horn","can_use_horn","expmul",
  74.   "unique","make_invisible","inv_locked",
  75.   "is_wooded","is_hilly","has_ready_skill","has_ready_weapon", 
  76.   "no_skill_ident","glow_radius","is_blind","can_see_in_dark",
  77.   "is_cauldron",
  78. #ifdef NPC_PROG
  79.   "npc_status","npc_program",
  80. #endif
  81. };
  82.  
  83. char *variables[NR_OF_VARIABLES];
  84.  
  85. /* This array equates the FLAG_ values with the V_ values.  Use -1 to
  86.  * put gaps in the array that should no be processed.
  87.  * The order matches the order of the define values in 'define.h'.
  88.  */
  89.  
  90. int flag_links[NUM_FLAGS+1][2] ={
  91. {FLAG_ALIVE, V_ALIVE}, {FLAG_WIZ, V_WIZ},
  92. {-1, -1}, {-1, -1},    /* REMOVED and FREED flags */
  93. {FLAG_WAS_WIZ, V_WAS_WIZ}, {FLAG_APPLIED, V_APPLIED},
  94. {FLAG_UNPAID, V_UNPAID}, {FLAG_AN, V_NEED_AN},
  95. {FLAG_NO_PICK, V_NO_PICK}, {FLAG_WALK_ON, V_WALK_ON},
  96. {FLAG_NO_PASS, V_NO_PASS},{FLAG_ANIMATE, V_IS_ANIMATED},
  97. {FLAG_SLOW_MOVE, -1}, {FLAG_FLYING, V_FLYING},
  98. {FLAG_MONSTER, V_MONSTER}, {FLAG_FRIENDLY, V_FRIENDLY},
  99. {FLAG_GENERATOR, V_GENERATOR}, {-1, -1},    /* FLAG_THROWN */
  100. {FLAG_AUTO_APPLY, V_AUTO_APPLY}, {FLAG_TREASURE, V_TREASURE},
  101. {FLAG_APPLY_ONCE, V_APPLY_ONCE},{FLAG_SEE_INVISIBLE, V_SEE_INVISIBLE},
  102. {FLAG_CAN_ROLL, V_CAN_ROLL}, {FLAG_IS_TURNING, V_IS_TURNING}, 
  103. {FLAG_IS_TURNABLE, V_IS_TURNABLE},{FLAG_WALK_OFF, V_WALK_OFF},
  104. {FLAG_FLY_ON, V_FLY_ON},{FLAG_FLY_OFF, V_FLY_OFF}, 
  105. {FLAG_IS_USED_UP, V_IS_USED_UP}, {FLAG_IDENTIFIED, V_IDENTIFIED},
  106. {FLAG_REFLECTING, V_REFLECTING}, {FLAG_CHANGING, V_CHANGING},
  107. {FLAG_SPLITTING, V_SPLITTING}, {FLAG_HITBACK, V_HITBACK},
  108. {FLAG_STARTEQUIP, V_STARTEQUIP}, {FLAG_BLOCKSVIEW, V_BLOCKSVIEW},
  109. {FLAG_UNDEAD, V_UNDEAD}, {FLAG_SCARED, V_SCARED},
  110. {FLAG_UNAGGRESSIVE, V_UNAGGRESSIVE}, {FLAG_REFL_MISSILE, V_REFLECT_MISSILE},
  111. {FLAG_REFL_SPELL, V_REFLECT_SPELL}, {FLAG_NO_MAGIC, V_NO_MAGIC},
  112. {FLAG_NO_FIX_PLAYER, V_NO_FIX_PLAYER}, {FLAG_NEED_IE, V_NEED_IE}, 
  113. {FLAG_TEAR_DOWN, V_TEAR_DOWN}, {FLAG_RUN_AWAY, V_RUN_AWAY},
  114. {FLAG_PASS_THRU, V_PASS_THRU}, {FLAG_CAN_PASS_THRU, V_CAN_PASS_THRU},
  115. {FLAG_PICK_UP, V_PICK_UP}, {FLAG_UNIQUE, V_UNIQUE},
  116. {FLAG_NO_DROP, V_NO_DROP}, {FLAG_NO_PRETEXT, V_NO_PRETEXT},
  117. {FLAG_CAST_SPELL, V_CAN_CAST_SPELL}, {FLAG_USE_SCROLL, V_CAN_USE_SCROLL},
  118. {FLAG_USE_WAND, V_CAN_USE_WAND},{FLAG_USE_BOW, V_CAN_USE_BOW},
  119. {FLAG_USE_ARMOUR, V_CAN_USE_ARMOUR},{FLAG_USE_WEAPON, V_CAN_USE_WEAPON},
  120. {FLAG_USE_RING, V_CAN_USE_RING}, {FLAG_READY_WAND, V_HAS_READY_WAND},
  121. {FLAG_READY_BOW, V_HAS_READY_BOW}, {FLAG_XRAYS, V_XRAYS},
  122. {-1, -1 /*NO_APPLY*/},  {FLAG_IS_FLOOR, V_IS_FLOOR},
  123. {FLAG_LIFESAVE, V_LIFESAVE}, {FLAG_NO_STRENGTH, V_NO_STRENGTH},
  124. {FLAG_SLEEP, V_SLEEP}, {FLAG_STAND_STILL, V_STAND_STILL},
  125. {FLAG_RANDOM_MOVE, V_RANDOM_MOVEMENT}, {FLAG_ONLY_ATTACK, V_ONLY_ATTACK},
  126. {FLAG_CONFUSED, V_CONFUSED}, {FLAG_STEALTH, V_STEALTH},
  127. {-1, -1 /*WIZPASS*/}, {-1, -1 /*IS_LINKED */},
  128. {FLAG_CURSED, V_CURSED}, {FLAG_DAMNED, V_DAMNED},
  129. {FLAG_SEE_ANYWHERE, V_SEE_ANYWHERE}, {FLAG_KNOWN_MAGICAL, V_KNOWN_MAGICAL},
  130. {FLAG_KNOWN_CURSED, V_KNOWN_CURSED}, {FLAG_CAN_STEAL, V_CAN_STEAL},
  131. {FLAG_BEEN_APPLIED, V_BEEN_APPLIED},  {FLAG_READY_ROD, V_HAS_READY_ROD},
  132. {FLAG_USE_ROD, V_CAN_USE_ROD}, {FLAG_READY_HORN, V_HAS_READY_HORN}, 
  133. {FLAG_USE_HORN, V_CAN_USE_HORN},{FLAG_MAKE_INVIS,V_MAKE_INVIS},
  134. {FLAG_INV_LOCKED,V_INV_LOCKED},{FLAG_IS_WOODED,V_IS_WOODED},
  135. {FLAG_IS_HILLY,V_IS_HILLY},{FLAG_READY_SKILL,V_HAS_READY_SKILL},
  136. {FLAG_READY_WEAPON,V_HAS_READY_WEAPON},{FLAG_NO_SKILL_IDENT,V_NO_SKILL_IDENT},
  137. {FLAG_BLIND,V_BLIND},{FLAG_SEE_IN_DARK,V_SEE_IN_DARK},
  138. {FLAG_IS_CAULDRON,V_IS_CAULDRON}
  139. };
  140.  
  141. void save_double(char *buf,char *name,double v)
  142. {
  143.   char tbuf[200];
  144.  
  145.   sprintf(tbuf,"%s %f\n",name,v);
  146.   strcat(buf,tbuf);
  147. }
  148.  
  149. /*
  150.  * Initialises the array of variable-names.  Needed before any
  151.  * objects can be loaded.  Called by init_library().
  152.  */
  153.  
  154. void init_vars() {
  155.   int i;
  156.   for(i=0;i<NR_OF_VARIABLES;i++)
  157.     variables[i]=add_string(variable_const[i]);
  158. }
  159.  
  160. /*
  161.  * Searches through all possible variables to find any that matches
  162.  * the given string.  An index to the variable_const[] array is returned,
  163.  * or -1 on failure.
  164.  */
  165.  
  166. int get_variable(char *name) {
  167.   int i;
  168.   char *tmp=find_string(name);
  169.   for(i=0;i<NR_OF_VARIABLES;i++)
  170.     if(variables[i]==tmp)
  171.       return i;
  172.   return -1;
  173. }
  174.  
  175. /*
  176.  * Returns a pointer to a static string which contains all variables
  177.  * which are different in the two given objects.
  178.  */
  179.  
  180. char *get_ob_diff(object *op,object *op2) {/* I plan to optimize this heavily */
  181.   static char buf2[HUGE_BUF];
  182.   static char buf[HUGE_BUF];
  183.   int tmp;
  184.  
  185.   buf[0]='\0';
  186.   if(op->name && op->name!=op2->name) {
  187.     sprintf(buf2,"name %s\n",op->name);
  188.     strcat(buf,buf2);
  189.   }
  190.   if(op->title && op->title!=op2->title) {
  191.     sprintf(buf2,"title %s\n", op->title);
  192.     strcat(buf, buf2);
  193.   }
  194.   if(op->race && op->race!=op2->race) {
  195.     sprintf(buf2,"race %s\n",op->race);
  196.     strcat(buf,buf2);
  197.   }
  198.   if(op->slaying && op->slaying!=op2->slaying) {
  199.     sprintf(buf2,"slaying %s\n",op->slaying);
  200.     strcat(buf,buf2);
  201.   }
  202.   if(op->msg && op->msg!=op2->msg) {
  203.     strcat(buf,"msg\n");
  204.     strcat(buf,op->msg);
  205.     strcat(buf,"endmsg\n");
  206.   }
  207.   if(op->other_arch!=op2->other_arch&&op->other_arch!=NULL && 
  208.      op->other_arch->name) {
  209.     sprintf(buf2,"other_arch %s\n",op->other_arch->name);
  210.     strcat(buf,buf2);
  211.   }
  212.   if(op->face!=op2->face) {
  213.       sprintf(buf2,"%s %s\n",variable_const[V_FACE], 
  214.         op->face->name);
  215.       strcat(buf,buf2);
  216.   }
  217.   if(op->stats.Str!=op2->stats.Str)
  218.     save_long(buf,variable_const[V_STR],op->stats.Str);
  219.   if(op->stats.Dex!=op2->stats.Dex)
  220.     save_long(buf,variable_const[V_DEX],op->stats.Dex);
  221.   if(op->stats.Con!=op2->stats.Con)
  222.     save_long(buf,variable_const[V_CON],op->stats.Con);
  223.   if(op->stats.Wis!=op2->stats.Wis)
  224.     save_long(buf,variable_const[V_WIS],op->stats.Wis);
  225.   if(op->stats.Pow!=op2->stats.Pow)
  226.     save_long(buf,variable_const[V_POW],op->stats.Pow);
  227.   if(op->stats.Cha!=op2->stats.Cha)
  228.     save_long(buf,variable_const[V_CHA],op->stats.Cha);
  229.   if(op->stats.Int!=op2->stats.Int)
  230.     save_long(buf,variable_const[V_INT],op->stats.Int);
  231.   if(op->stats.hp!=op2->stats.hp)
  232.     save_long(buf,variable_const[V_HP],op->stats.hp);
  233.   if(op->stats.maxhp!=op2->stats.maxhp)
  234.     save_long(buf,variable_const[V_MAXHP],op->stats.maxhp);
  235.   if(op->stats.sp!=op2->stats.sp)
  236.     save_long(buf,variable_const[V_SP],op->stats.sp);
  237.   if(op->stats.maxsp!=op2->stats.maxsp)
  238.     save_long(buf,variable_const[V_MAXSP],op->stats.maxsp);
  239.   if(op->stats.grace!=op2->stats.grace)
  240.     save_long(buf,variable_const[V_GRACE],op->stats.grace);
  241.   if(op->stats.maxgrace!=op2->stats.maxgrace)
  242.     save_long(buf,variable_const[V_MAXGRACE],op->stats.maxgrace);
  243.   if(op->stats.exp!=op2->stats.exp)
  244.     save_long(buf,variable_const[V_EXP],op->stats.exp);
  245.   if(op->expmul!=op2->expmul) 
  246.     save_double(buf,variable_const[V_EXPMUL],op->expmul);
  247.   if(op->stats.food!=op2->stats.food)
  248.     save_long(buf,variable_const[V_FOOD],op->stats.food);
  249.   if(op->stats.dam!=op2->stats.dam)
  250.     save_long(buf,variable_const[V_DAM],op->stats.dam);
  251.   if(op->stats.luck!=op2->stats.luck)
  252.     save_long(buf,variable_const[V_LUCK],op->stats.luck);
  253.   if(op->stats.wc!=op2->stats.wc)
  254.     save_long(buf,variable_const[V_WC],op->stats.wc);
  255.   if(op->stats.ac!=op2->stats.ac)
  256.     save_long(buf,variable_const[V_AC],op->stats.ac);
  257.   if(op->armour!=op2->armour)
  258.     save_long(buf,variable_const[V_ARMOUR],op->armour);
  259.   if(op->x!=op2->x) 
  260.     save_long(buf,variable_const[V_X],op->x);
  261.   if(op->y!=op2->y)
  262.     save_long(buf,variable_const[V_Y],op->y);
  263.   if(op->speed!=op2->speed) {
  264.     sprintf(buf2,"speed %f\n",op->speed);
  265.     strcat(buf,buf2);
  266.   }
  267.   if(op->speed > 0 && op->speed_left!=op2->speed_left) {
  268.     sprintf(buf2,"speed_left %f\n",op->speed_left);
  269.     strcat(buf,buf2);
  270.   }
  271.   if(op->move_status != op2->move_status)
  272.     save_long(buf,variable_const[V_MOVE_STATUS],op->move_status);
  273.   if(op->move_type != op2->move_type)
  274.     save_long(buf,variable_const[V_ATT_MOVE],op->move_type);
  275.   if(op->nrof!=op2->nrof)
  276.     save_long(buf,variable_const[V_NROF],op->nrof);
  277.   if(op->level!=op2->level)
  278.     save_long(buf,variable_const[V_LEVEL],op->level);
  279.   if(op->direction!=op2->direction)
  280.     save_long(buf,variable_const[V_DIRECTION],op->direction);
  281.   if(op->type!=op2->type)
  282.     save_long(buf,variable_const[V_TYPE],op->type);
  283.   if(op->immune!=op2->immune)
  284.     save_long(buf,variable_const[V_IMMUNE],op->immune);
  285.   if(op->protected!=op2->protected)
  286.     save_long(buf,variable_const[V_PROTECTED],op->protected);
  287.   if(op->attacktype!=op2->attacktype)
  288.     save_long(buf,variable_const[V_ATTACKTYPE],op->attacktype);
  289.   if(op->vulnerable!=op2->vulnerable)
  290.     save_long(buf,variable_const[V_VULNERABLE],op->vulnerable);
  291.   if(op->path_attuned!=op2->path_attuned)
  292.     save_long(buf,variable_const[V_PATH_ATTUNED],op->path_attuned);
  293.   if(op->path_repelled!=op2->path_repelled)
  294.     save_long(buf,variable_const[V_PATH_REPELLED],op->path_repelled);
  295.   if(op->path_denied!=op2->path_denied)
  296.     save_long(buf,variable_const[V_PATH_DENIED],op->path_denied);
  297.   if(op->material!=op2->material)
  298.     save_long(buf,variable_const[V_MATERIAL],op->material);
  299.   if(op->value!=op2->value)
  300.     save_long(buf,variable_const[V_VALUE],op->value);
  301.   if(op->carrying!=op2->carrying)
  302.     save_long(buf,variable_const[V_CARRYING],op->carrying);
  303.   if(op->weight!=op2->weight)
  304.     save_long(buf,variable_const[V_WEIGHT],op->weight);
  305.   if(op->invisible!=op2->invisible)
  306.     save_long(buf,variable_const[V_INVISIBLE],op->invisible);
  307.   if(op->state!=op2->state)
  308.     save_long(buf,variable_const[V_STATE],op->state);
  309.   if(op->magic!=op2->magic)
  310.     save_long(buf,variable_const[V_MAGIC],op->magic);
  311.   if(op->last_heal!=op2->last_heal)
  312.     save_long(buf,variable_const[V_LAST_HEAL],op->last_heal);
  313.   if(op->last_sp!=op2->last_sp)
  314.     save_long(buf,variable_const[V_LAST_SP],op->last_sp);
  315.   if(op->last_eat!=op2->last_eat)
  316.     save_long(buf,variable_const[V_LAST_EAT],op->last_eat);
  317.   if(QUERY_FLAG(op,FLAG_IS_LINKED) && (tmp = get_button_value(op)))
  318.     save_long(buf,variable_const[V_CONNECTED],tmp);
  319.   if(op->glow_radius!=op2->glow_radius) 
  320.     save_long(buf,variable_const[V_GLOW_RADIUS],op->glow_radius);
  321. #ifdef NPC_PROG
  322.   if(op->npc_status!=op2->npc_status)
  323.     save_long(buf,variable_const[V_NPC_STATUS],op->npc_status);
  324.   if(op->npc_program!=op2->npc_program)
  325.     save_long(buf,variable_const[V_NPC_PROGRAM],op->npc_program);
  326. #endif
  327.  
  328. #if 0
  329.   if(op->run_away!=op2->run_away)
  330.     save_long(buf,variable_const[V_EDITABLE],op->arch->editable);
  331. #endif
  332.  
  333. /* Eneq(@csd.uu.se): Handles run_away and pick_up */
  334.   if(op->run_away!=op2->run_away)
  335.     save_long(buf,variable_const[V_RUN_AWAY],op->run_away);
  336.   if(op->pick_up!=op2->pick_up)
  337.     save_long(buf,variable_const[V_PICK_UP],op->pick_up);
  338.  
  339. /* Vick (@bern.docs.uu.se) @921107 -> Handle 'will_apply' &
  340.    'random_movement.*/
  341.  
  342.   if (op->will_apply!=op2->will_apply)
  343.     save_long(buf,variable_const[V_WILL_APPLY],op->will_apply);
  344.  
  345. /* Mol(@meryl.csd.uu.se) 921108  Handle can_apply */
  346.   if (op->can_apply!=op2->can_apply)
  347.     save_long(buf,variable_const[V_CAN_APPLY],op->can_apply);
  348.  
  349.   for (tmp=0; tmp <= NUM_FLAGS; tmp++) {
  350.     if ((flag_links[tmp][0]!=-1) && (QUERY_FLAG(op, flag_links[tmp][0]) != 
  351.     QUERY_FLAG(op2, flag_links[tmp][0]))) {
  352.         if (flag_links[tmp][0]==FLAG_SLOW_MOVE) {
  353.         sprintf(buf2,"%s %f\n",variable_const[V_SLOW_MOVE],SLOW_PENALTY(op));
  354.         strcat(buf,buf2);
  355.         }
  356.         else 
  357.             BUFADD(QUERY_FLAG(op, flag_links[tmp][0]), flag_links[tmp][1]);
  358.     }
  359.   }
  360.   if(buf[0]=='\0')
  361.     return NULL;
  362.   return buf;
  363. }
  364.  
  365. /*
  366.  * Dumps all variables in an object to a file.
  367.  * If bit 0 of flag is set, unpaid objects will be saved.
  368.  * If bit 1 of flag is set, don't remove the object after save.
  369.  */
  370.  
  371. void save_object(FILE *fp,object *op, int flag) {
  372.   archetype *at;
  373.   char *cp;
  374.   object *tmp,*old;
  375.  
  376.   if(op->owner!=NULL || fp == NULL)
  377.     return;
  378.   if(!(flag&1)&&(QUERY_FLAG(op, FLAG_UNPAID))) {
  379. #if 0
  380.     remove_ob(op);
  381.     free_object(op);
  382. #endif
  383.     return;
  384.   }
  385.   if((at=op->arch)!=NULL)
  386.     fprintf(fp,"arch %s\n",at->name);
  387.   if((cp=get_ob_diff(op,&((at==NULL?empty_archetype:at)->clone)))!=NULL)
  388.     fputs(cp,fp);
  389.  
  390. /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents*/
  391.  
  392.   old=NULL;
  393.  
  394.   if (flag & 2 )
  395.     for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  396.       save_object(fp,tmp,flag);
  397.   else while ((tmp=op->inv)!=NULL) {
  398.     if(old==tmp) {
  399.       LOG(llevError,"Recursive loop in inventory\n");
  400.       break;
  401.     }
  402.     save_object(fp,tmp,flag); 
  403.     old=tmp;
  404.   }
  405.    
  406.   if (!(flag&2)) {
  407.       remove_ob(op);
  408.       free_object (op);
  409.   }
  410.  
  411.   fprintf(fp,"end\n");
  412. }
  413.  
  414.  
  415. /*
  416.  * set_variable() expects buf to be a line with two arguments, the first
  417.  * being a variable and the second being the value (which can be anything from
  418.  * an integer to a string). 
  419.  * The object given will have the given variable modified.
  420.  *
  421.  * -1 will be returned if there is no such variable
  422.  * 0 will be returned if the variable is to be ignored
  423.  * 1 will be returned if the variable was "anim"
  424.  * 2 will be returned if the variable was "end"
  425.  * 3 will be returned if the variable was "Inventory"
  426.  * 4 will be returned if the variable was "More"
  427.  * 5 will be returned if the variable was "msg"
  428.  * 6 will be returned if the variable was "endmsg"
  429.  * otherwise 0 will be returned
  430.  */
  431.  
  432. int set_variable(object *op,char *buf) {
  433.   char *vbp;
  434.   int value,tmp,var;
  435.  
  436.   if((vbp=strchr(buf,'\n'))!=NULL) /* Change newline into end of string */
  437.     *vbp='\0';
  438.   else
  439.     LOG(llevDebug, "Line too long.\n");
  440.   if((vbp=strchr(buf,' '))==NULL) /* No argument to the variable */
  441.     value=0,vbp=NULL;
  442.   else {
  443.     *vbp='\0',vbp++;
  444.     value=atol(vbp);
  445.   }
  446.   switch(var=get_variable(buf)) {
  447.   case V_ARCH:
  448.     op->arch=find_archetype(vbp);
  449.     if(op->arch!=NULL)
  450.       copy_object(&op->arch->clone,op);
  451.     break;
  452.   case V_OTHER_ARCH:
  453.     op->other_arch=find_archetype(vbp);
  454.     break;
  455.   case V_RACE:
  456.     if(op->race!=NULL)
  457.       free_string(op->race);
  458.     op->race=add_string(vbp);
  459.     break;
  460.   case V_SLAYING:
  461.     if(op->slaying!=NULL)
  462.       free_string(op->slaying);
  463.     op->slaying=add_string(vbp);
  464.     break;
  465.   case V_MSG:
  466.     return 5;
  467.   case V_MSGEND:
  468.     return 6;
  469.   case V_INVENTORY:
  470.     return 3;
  471.   case V_MORE:
  472.     return 4;
  473.   case V_ANIM:
  474.     if(op->arch==NULL) {
  475.       LOG(llevError,"Got animation in object without archetype:\n");
  476.       return 0;
  477.     }
  478.     SET_FLAG(op,FLAG_ANIMATE);
  479.     return 1;
  480.   case V_END:
  481.     return 2;
  482.   case V_OBJECT:
  483.     if(vbp==NULL) {
  484.       LOG(llevError,"Object lacks name.\n");
  485.       return 0;
  486.     }
  487.     if(op->arch!=NULL)
  488.       op->arch->name=add_string(vbp);
  489.     op->name=add_string(vbp);
  490.     break;
  491.   case V_NAME:
  492.     if(*vbp=='\0') {
  493.       LOG(llevError,"name without name\n");
  494.       break;
  495.     }
  496.     if(op->name!=NULL)
  497.       free_string(op->name);
  498.     op->name=add_string(vbp);
  499.     break;
  500.   case V_TITLE:
  501.     if(*vbp=='\0') {
  502.       LOG(llevError, "title without name\n");
  503.       break;
  504.     }
  505.     if(op->title!=NULL)
  506.       free_string(op->title);
  507.     op->title = add_string(vbp);
  508.     break;
  509.   case V_SPEED:
  510.     sscanf(vbp,"%f",&op->speed);
  511.     if (op->speed<0)
  512.       op->speed_left=op->speed_left-RANDOM()%100/100.0;
  513.     update_ob_speed(op);
  514.     break;
  515.   case V_SPEED_LEFT:
  516.     sscanf(vbp,"%f",&op->speed_left);
  517.     break;
  518.   case V_SLOW_MOVE:
  519.     {
  520.       float f;
  521.       sscanf(vbp,"%f",&f);
  522.       SET_SLOW_PENALTY(op,f);
  523.       SET_FLAG(op,FLAG_SLOW_MOVE);
  524.     }
  525.     break;
  526. /* Eneq(@csd.uu.se): Added handleof archetype-field anim_speed */
  527.  
  528.   case V_ANIM_SPEED:
  529.     op->anim_speed = (unsigned char) value;
  530.     break;
  531. /* kholland @ sunlab.cit.cornell.edu added move_type and status */
  532.   case V_ATT_MOVE:
  533.     op->move_type = (unsigned short) value;
  534.     break;
  535.   case V_MOVE_STATUS:
  536.     op->move_status = (signed long) value;
  537.     break;
  538. /*
  539.  * Eneq(@csd.uu.se): Added handle of container <no> where no is containers
  540.  * weight limit, and no_drop which makes an item undroppable
  541.  */
  542.   case V_CONTAINER:
  543.     op->weight_limit=(signed long) value;
  544.     break;
  545.   case V_FACE:
  546. #if 0
  547.     op->face.number=(Fontindex)FindFace (vbp,0);
  548. #else
  549.     op->face = &new_faces[FindFace(vbp,0)];
  550. #endif
  551.     break;
  552.   case V_COLOR_FG:
  553. #if 0
  554.     op->face.fg = find_color(vbp);
  555. #else
  556. /*    LOG(llevDebug,"Got object with color set: %s\n", vbp);*/
  557. #endif
  558.     break;
  559.   case V_COLOR_BG:
  560. #if 0
  561.     op->face.bg = find_color(vbp);
  562. #else
  563. /*    LOG(llevDebug,"Got object with color set: %s\n", vbp);*/
  564. #endif
  565.     break;
  566.   case V_STR:
  567.     op->stats.Str=(signed char) value;
  568.     break;
  569.   case V_DEX:
  570.     op->stats.Dex=(signed char) value;
  571.     break;
  572.   case V_CON:
  573.     op->stats.Con=(signed char) value;
  574.     break;
  575.   case V_WIS:
  576.     op->stats.Wis=(signed char) value;
  577.     break;
  578.   case V_POW:
  579.     op->stats.Pow=(signed char) value;
  580.     break;
  581.   case V_CHA:
  582.     op->stats.Cha=(signed char) value;
  583.     break;
  584.   case V_INT:
  585.     op->stats.Int=(signed char) value;
  586.     break;
  587.   case V_HP:
  588.     op->stats.hp=(signed short) value;
  589.     break;
  590.   case V_MAXHP:
  591.     op->stats.maxhp=(signed short) value;
  592.     break;
  593.   case V_SP:
  594.     op->stats.sp=(signed short) value;
  595.     break;
  596.   case V_MAXSP:
  597.     op->stats.maxsp=(signed short) value;
  598.     break;
  599.   case V_GRACE:
  600.     op->stats.grace=(signed short) value;
  601.     break;
  602.   case V_MAXGRACE:
  603.     op->stats.maxgrace=(signed short) value;
  604.     break;
  605.   case V_EXP:
  606.     op->stats.exp=(signed long) value;
  607.     break;
  608.   case V_EXPMUL:
  609.     sscanf(vbp,"%lf",&(op->expmul));
  610.     break;
  611.   case V_FOOD:
  612.     op->stats.food=(signed short) value;
  613.     break;
  614.   case V_DAM:
  615.     op->stats.dam=(sint16) value;
  616.     break;
  617.   case V_LUCK:
  618.     op->stats.luck=(signed char) value;
  619.     break;
  620.   case V_WC:
  621.     op->stats.wc=(signed char) value;
  622.     break;
  623.   case V_AC:
  624.     op->stats.ac=(signed char) value;
  625.     break;
  626.   case V_ARMOUR:
  627.     op->armour=(signed char) value;
  628.     break;
  629.   case V_X:
  630.     op->x=(signed short) value,
  631.     op->ox=(signed short) value;
  632.     break;
  633.   case V_Y:
  634.     op->y=(signed short) value,
  635.     op->oy=(signed short) value;
  636.     break;
  637.   case V_NROF:
  638.     op->nrof=(unsigned long) value;
  639.     break;
  640.   case V_LEVEL:
  641.     op->level=(signed char) value;
  642.     break;
  643.   case V_DIRECTION:
  644.     op->direction=(signed char) value;
  645.     break;
  646.   case V_TYPE:
  647.     op->type=(unsigned char) value;
  648.     break;
  649.   case V_IMMUNE:
  650.     op->immune=(unsigned int) value;
  651.     break;
  652.   case V_PROTECTED:
  653.     op->protected=(unsigned int) value;
  654.     break;
  655.   case V_ATTACKTYPE:
  656.     op->attacktype=(unsigned int) value;
  657.     break;
  658.   case V_VULNERABLE:
  659.     op->vulnerable=(unsigned int) value;
  660.     break;
  661.   case V_PATH_ATTUNED:
  662.     op->path_attuned=(uint32) value;
  663.     break;
  664.   case V_PATH_REPELLED:
  665.     op->path_repelled=(uint32) value;
  666.     break;
  667.   case V_PATH_DENIED:
  668.     op->path_denied=(uint32) value;
  669.     break;
  670.   case V_MATERIAL:
  671.     op->material=(uint16) value;
  672.     break;
  673.   case V_VALUE:
  674.     op->value=(signed long) value;
  675.     break;
  676.   case V_CARRYING:
  677.     op->carrying=(signed long) value;
  678.     break;
  679.   case V_WEIGHT:
  680.     op->weight=(signed long) value;
  681.     break;
  682.   case V_INVISIBLE:
  683.     op->invisible=(signed short) value;
  684.     break;
  685.   case V_MAGIC:
  686.     op->magic=(unsigned char) value;
  687.     break;
  688.   case V_STATE:
  689.     op->state=(unsigned char) value;
  690.     break;
  691.   case V_LAST_HEAL:
  692.     op->last_heal=(signed short) value;
  693.     break;
  694.   case V_LAST_SP:
  695.     op->last_sp=(signed short) value;
  696.     break;
  697.   case V_LAST_EAT:
  698.     op->last_eat=(signed short) value;
  699.     break;
  700.   case V_CONNECTED:
  701.     add_button_link(op, op->map, value);
  702.     break;
  703. #ifdef NPC_PROG
  704.   case V_NPC_STATUS:
  705.     op->npc_status=(unsigned short) value;
  706.     break;
  707.   case V_NPC_PROGRAM:
  708.     op->npc_program=(unsigned short) value;
  709.     break;
  710. #endif
  711.  
  712.   case V_EDITABLE:
  713.     op->arch->editable = value;
  714.     break;
  715.  
  716. /* Eneq(@csd.uu.se): Handle PICK_UP */
  717.  
  718.   case V_PICK_UP:
  719.     op->pick_up=(unsigned char) value;
  720.     break;
  721.  
  722. /* Eneq(@csd.uu.se): Handle RUN_AWAY, (CAN_)PASS_THRU. */
  723.  
  724.   case V_RUN_AWAY:
  725.     op->run_away = (unsigned short) value;
  726.     break;
  727.  
  728. /* Vick's (vick@bern.docs.uu.se) patch 921107 : will_apply, which
  729.    enables a monster to apply things on the ground. */
  730.  
  731.   case V_WILL_APPLY:
  732.     op->will_apply = (unsigned char) value;
  733.     break;
  734.  
  735.   case V_GLOW_RADIUS:
  736.     op->glow_radius = (signed short) value;
  737.     break;
  738.  
  739. /* Note: With the new FLAG value method, most all of these bits are
  740.  * set in the default area.  The only ones not set there are
  741.  * special cases (those needing to check the object, print debugging
  742.  * messages, or SET/CLEAR multiple flags.
  743.  */
  744.  
  745.   case V_WIZ:
  746.     if (value) {
  747.     SET_FLAG(op, FLAG_WIZ);
  748.     SET_FLAG(op, FLAG_WAS_WIZ);
  749.     SET_FLAG(op, FLAG_WIZPASS);
  750.     }
  751.     else {
  752.     CLEAR_FLAG(op, FLAG_WIZ);
  753.     CLEAR_FLAG(op, FLAG_WIZPASS);
  754.     }
  755.     break;
  756.  
  757. /* Mol(@csd.docs.uu.se) patch 921108 : can_apply, is similair to will_apply,
  758.    but applies thing it has picked up. */
  759.  
  760.   case V_CAN_APPLY:
  761.     op->can_apply = (unsigned char) value;
  762.     break;
  763.  
  764.   case V_FRIENDLY:
  765.     if(value) {
  766.       SET_FLAG(op,FLAG_FRIENDLY);
  767.       if (op->type != PLAYER) {
  768.         LOG(llevDebug, "Adding friendly object %s.\n",op->name);
  769.         add_friendly_object(op);
  770.       }
  771.     }
  772.     else
  773.       CLEAR_FLAG(op,FLAG_FRIENDLY);
  774.     break;
  775.  
  776.   case V_IDENTIFIED:
  777.     if(value) {
  778.       SET_FLAG(op,FLAG_IDENTIFIED);
  779.       CLEAR_FLAG(op, FLAG_KNOWN_MAGICAL);
  780.     }
  781.     else
  782.       CLEAR_FLAG(op,FLAG_IDENTIFIED);
  783.     break;
  784.  
  785.   case V_WAS_WIZ:
  786.     if(value)
  787.       SET_FLAG(op,FLAG_WAS_WIZ);
  788.     else
  789.       CLEAR_FLAG(op,FLAG_WAS_WIZ);
  790.     break;
  791.  
  792.  /* In the default statement, it will handle all cases above.
  793.   * First search through the flag_links, to match corresponding
  794.   * variables.  IF it doesn't find anything, then to the check for
  795.   * randomitems, and then print the error messages.
  796.   */
  797.   default:
  798.     for (tmp=0; tmp<=NUM_FLAGS; tmp++) {
  799.     if (flag_links[tmp][1]==var) {
  800.         if (value) SET_FLAG(op, flag_links[tmp][0]);
  801.         else CLEAR_FLAG(op, flag_links[tmp][0]);
  802.         return 0;
  803.     }
  804.     }
  805.     if(!strcmp(buf,"randomitems"))
  806.       return 0;
  807.     sprintf(errmsg,"Warning, unknown (or oldfashioned) variable: %s",buf);
  808.     return -1;
  809.   }
  810.   return 0;
  811. }
  812.  
  813. /*
  814.  * Loads an object from the given file-pointer.
  815.  * Variables will be read and parsed and patched into the object
  816.  * until the string "end" is reached, or the end of the file.
  817.  * If EOF is reached, it returnes false, otherwise true.
  818.  */
  819.  
  820. int load_object(FILE *fp, object *op) {
  821.   char buf[MAX_BUF];
  822.   char msgbuf[HUGE_BUF];
  823.   Fontindex faces[MAX_ANIMATIONS];
  824.   int position=1; /* 1 = standalone, 2 = inventory, 3 = head/tail link */
  825.   int anim_start=0,msg_start=0;
  826.   object *tmp;
  827.  
  828.   buf[MAX_BUF - 1] = '\0';
  829.   while(fgets(buf,sizeof(buf),fp)!=NULL) {
  830.     if(*buf=='#')
  831.       continue;
  832.     if(anim_start) {
  833.       if(!strncmp("mina",buf,4)) {
  834.         op->arch->animations=anim_start-1,anim_start=0;
  835.         op->arch->faces = (Fontindex *) malloc
  836.         (sizeof(Fontindex) * (op->arch->animations+1));
  837.         memcpy((void *)op->arch->faces,(void *)faces,
  838.                (op->arch->animations+1)*sizeof(Fontindex));
  839.       } else {
  840.       faces[anim_start - 1] = FindFace(buf,0);
  841.       anim_start++;
  842.       }
  843.       continue;
  844.     }
  845.     if(msg_start&&strncmp(buf,"endmsg",6)) {
  846.       strcat(msgbuf,buf);
  847.       continue;
  848.     }
  849.     /* found an arch in the object.  Must be part of the
  850.      * objects inventory.
  851.      */
  852.     if(!strncmp(buf,"arch ",5)&&op->arch!=NULL) {
  853.         object *otmp;
  854.  
  855.         tmp=get_object();
  856.     set_variable(tmp, buf);
  857.         load_object(fp, tmp);
  858.         if (op->inv!=NULL) {
  859.             for (otmp=op->inv; otmp->below!=NULL; otmp=otmp->below);
  860.             otmp->below=tmp;
  861.         }
  862.     else op->inv=tmp;
  863.         return load_object (fp, op);
  864.     }
  865.     switch(set_variable(op,buf)) {
  866.     case -1:
  867.       LOG(llevError,"%s\n",errmsg);
  868.       break;
  869.     case 1:
  870.       anim_start=1;
  871.       break;
  872.     case 2:
  873.       return position;
  874.     case 3:
  875.       position=2;
  876.       break;
  877.     case 4:
  878.       position=3;
  879.       break;
  880.     case 5:
  881.       msg_start=1;
  882.       msgbuf[0]='\0';
  883.       break;
  884.     case 6:
  885.       msg_start=0;
  886.       op->msg=add_string(msgbuf);
  887.       if (strlen(op->msg) > 500)
  888.         LOG(llevDebug, "message: %d\n", strlen(op->msg));
  889.       break;
  890.     }
  891.   }
  892.   return 0;
  893. }
  894.  
  895.  
  896. /*
  897.  * Loads an object from the given file-pointer.
  898.  * Variables will be read and parsed and patched into the object
  899.  * until the string "end" is reached, or the end of the file.
  900.  * If EOF is reached, it returnes false, otherwise true.
  901.  */
  902.  
  903. enum LoadState { unknown, arch, anim, message };
  904.  
  905. object *LoadObject (FILE *fp, char *inbuf) {
  906.     char buf[256];
  907.     char msgbuf[HUGE_BUF];
  908.     Fontindex faces[MAX_ANIMATIONS];
  909.     int anim_start = 0;
  910.     object *op = NULL;
  911.     enum LoadState state = unknown;
  912.     
  913.    if (inbuf!=NULL) {
  914.      if (strncmp("arch", inbuf, 4))
  915.     LOG (llevError, "parse error in inbuf: %s\n (expecting arch)", inbuf);
  916.       else {
  917.     state = arch;
  918.     op = get_object();
  919.     set_variable (op, inbuf);
  920.       }
  921.    }
  922.  
  923.     while(fgets(buf,sizeof(buf),fp)!=NULL) {
  924.     if(*buf=='#')
  925.         continue;
  926.  
  927.     switch (state) {
  928.       case unknown:
  929.         if (strncmp ("arch", buf, 4))
  930.         LOG (llevError, "parse error in: %s\n (expecting arch)", buf);
  931.         else {
  932.         state = arch;
  933.         op = get_object();
  934.         set_variable (op, buf);
  935.         }
  936.         break;
  937.  
  938.       case arch:
  939.         if(!strncmp (buf, "arch ", 5)) {
  940.         object *tmp;
  941.         tmp = LoadObject(fp,buf);
  942.         (void) insert_ob_in_ob (tmp, op);
  943.         break;
  944.         }
  945.  
  946.         switch(set_variable (op, buf)) {
  947.           case -1:
  948.         LOG(llevError,"%s\n",errmsg);
  949.         break;
  950.         
  951.           case 0:
  952.         break;
  953.  
  954.           case 1:
  955.         state = anim;
  956.         anim_start = 0;
  957.         break;
  958.  
  959.           case 2:
  960.         return op;
  961.  
  962.           case 5:
  963.         state = message;
  964.         msgbuf[0] = '\0';
  965.         break;
  966.  
  967.           default:
  968.         LOG(llevError,"LoadObject()\n");
  969.         break;
  970.         }       
  971.         break;
  972.  
  973.       case anim:
  974.         if(!strncmp ("mina", buf, 4)) {
  975.         op->arch->animations = anim_start;
  976.         op->arch->faces = (Fontindex *) malloc (sizeof (Fontindex) * anim_start);
  977.         memcpy(op->arch->faces, faces, anim_start * sizeof (Fontindex));
  978.         state = arch;
  979.         break;
  980.         }
  981.         faces[anim_start++] = FindFace(buf,0);
  982.         break;
  983.  
  984.       case message:
  985.         if(!strncmp (buf, "endmsg", 6)) {
  986.         op->msg = add_string (msgbuf);
  987.         state = arch;
  988.         break;
  989.         }
  990.         strcat(msgbuf,buf);
  991.     }
  992.     }
  993.     if (op)
  994.     free_object (op);
  995.  
  996.     return NULL;
  997. }
  998.  
  999.